package dev.ece.util.io.tga;

import java.awt.image.BufferedImage;
import java.io.IOException;
import java.nio.ByteOrder;
import java.util.Iterator;

import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.ImageTypeSpecifier;
import javax.imageio.metadata.IIOMetadata;
import javax.imageio.spi.ImageReaderSpi;
import javax.imageio.stream.ImageInputStream;

public class TGAImageReader extends ImageReader {

	private TGAHeader header;
	
	protected TGAImageReader(ImageReaderSpi originatingProvider) {
		super(originatingProvider);
	}

	@Override
	public int getNumImages(boolean allowSearch) throws IOException {
		return 1;
	}

	@Override
	public int getWidth(int imageIndex) throws IOException {
		return header.getWidth();
	}

	@Override
	public int getHeight(int imageIndex) throws IOException {
		return header.getHeight();
	}

	@Override
	public Iterator<ImageTypeSpecifier> getImageTypes(int imageIndex) throws IOException {
		return null;
	}

	@Override
	public IIOMetadata getStreamMetadata() throws IOException {
		return null;
	}

	@Override
	public IIOMetadata getImageMetadata(int imageIndex) throws IOException {
		return null;
	}

	@Override
	public BufferedImage read(int imageIndex, ImageReadParam param) throws IOException {
		if (imageIndex != 0) {
			throw new IndexOutOfBoundsException("imageIndex != 0!");
	    }
		ImageInputStream stream = (ImageInputStream) input;
		ByteOrder byteOrder = stream.getByteOrder();
        stream.setByteOrder(ByteOrder.LITTLE_ENDIAN);
		header = TGAHeader.readTGAHeader(stream);
		int bytesPerPixel = header.getBits() / 8;
		boolean hasAlpha = bytesPerPixel > 3;
		int imageType = hasAlpha ? BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_INT_RGB;
		int imageSize = header.getWidth() * header.getHeight();
		try {
			if(header.getImagetype() == 2) {
				int[] pixels = new int[imageSize];
				int[] pixel = new int[bytesPerPixel];
				for(int i=0; i<imageSize; i++) {
					for(int j=0; j<bytesPerPixel; j++) {
						pixel[j] = stream.readByte() & 0xFF;
					}
					if(hasAlpha) {
						pixels[i] = 0x00000000 | (pixel[3] << 24) | (pixel[2] << 16) | (pixel[1] << 8) | pixel[0];
					} else {
						pixels[i] = 0xff000000 | (pixel[2] << 16) | (pixel[1] << 8) | pixel[0];
					}
				}
				BufferedImage image = new BufferedImage(header.getWidth(), header.getHeight(), imageType);
				image.setRGB(0, 0, header.getWidth(), header.getHeight(), pixels, 0, header.getWidth());
				return image;
				//未压缩
			} else if(header.getImagetype() == 10) {
				//RLE压缩
				return null;
			}
		} finally {
			stream.setByteOrder(byteOrder);
		}
		return null;
	}

	public static class TGAHeader {
		
		/**
		 * size of ID field that follows 18 byte header (0 usually)  
		 */
		private byte identsize;
		/**
		 * type of colour map 
		 * 0=none, 1=has palette
		 */
		private byte colourmaptype;
		
		/**
		 *  type of image 
		 *  0=none,1=indexed,2=rgb, 3=grey,+8=rle packed
		 */
		private byte imagetype;
		
		/**
		 * first colour map entry in palette
		 */
		private short colourmapstart;
		
		/**
		 * number of colours in palette
		 */
		private short colourmaplength;
		
		/**
		 * number of bits per palette entry 15,16,24,32
		 */
		private byte colourmapbits;
		
		/**
		 * image x origin
		 */
		private short xstart;
		
		/**
		 * image y origin
		 */
		private short ystart;
		/**
		 * image width in pixels
		 */
		private int width;
		/**
		 * image height in pixels
		 */
		private int height;
		/**
		 *  image bits per pixel 8,16,24,32
		 */
		private byte bits;
		
		/**
		 *  image descriptor bits (vh flip bits)
		 */
		private byte descriptor;

		public static TGAHeader readTGAHeader(ImageInputStream input) throws IOException {
			TGAHeader header = new TGAHeader();
			header.identsize = input.readByte();
			header.colourmaptype = input.readByte();
			header.imagetype = input.readByte();
			header.colourmapstart = input.readShort();
			header.colourmaplength = input.readShort();
			header.colourmapbits = input.readByte();
			header.xstart = input.readShort();
			header.ystart = input.readShort();
			header.width = input.readShort();
			header.height = input.readShort();
			header.bits = input.readByte();
			header.descriptor = input.readByte();
			return header;
		}
		
		public byte getIdentsize() {
			return identsize;
		}

		public byte getColourmaptype() {
			return colourmaptype;
		}

		public byte getImagetype() {
			return imagetype;
		}

		public short getColourmapstart() {
			return colourmapstart;
		}

		public short getColourmaplength() {
			return colourmaplength;
		}

		public byte getColourmapbits() {
			return colourmapbits;
		}

		public short getXstart() {
			return xstart;
		}

		public short getYstart() {
			return ystart;
		}

		public int getWidth() {
			return width;
		}

		public int getHeight() {
			return height;
		}

		public byte getBits() {
			return bits;
		}

		public byte getDescriptor() {
			return descriptor;
		}

		@Override
		public String toString() {
			String string = new StringBuilder()
				.append("identsize:%s,colourmaptype:%s,imagetype:%s,colourmapstart:%s,colourmaplength:%s,")
				.append("colourmapbits:%s,xstart:%s,ystart:%s,width:%s,height:%s,bits:%s,descriptor:%s")
				.toString();
			return String.format(string, 
					identsize, colourmaptype, imagetype,colourmapstart, colourmaplength,
					colourmapbits,xstart,ystart,width,height,bits,descriptor);
		}
		
	}
	
}
